#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <unordered_map>
#include "Connection.hpp"
#include "Log.hpp"
#include "Multiplex.hpp"
#include "InetAddr.hpp"
using namespace ns_log;

class Reactor
{
    static const int gnum = 128;
private:
    void OnceLoop(int timeout)
    {
        int n = _epoller->Wait(revents, gnum, timeout);
        for (int i = 0; i < n; i++)
        {
            int fd = revents[i].data.fd;
            uint32_t revent = revents[i].events;
            // 处理读写事件
            if (revent & EPOLLERR)
                revent |= (EPOLLIN | EPOLLOUT);
            if (revent & EPOLLHUP)
                revent |= (EPOLLIN | EPOLLOUT);
            if (revent & EPOLLIN)
            {
                // 如果回调事件存在并且fd在_connections中,处理读事件
                if (IsConnectionExist(fd) && _connections[fd]->_recv_handle)
                {
                    _connections[fd]->_recv_handle(_connections[fd]);
                }
            }
            if (revent & EPOLLOUT)
            {
                // 处理写事件
                if (IsConnectionExist(fd) && _connections[fd]->_send_handle)
                {
                    _connections[fd]->_send_handle(_connections[fd]);
                }
            }
        }
    }

public:
    Reactor() : _epoller(std::make_unique<Epoller>())
    {
    }
    void AddConnection(int fd, uint32_t events, const InetAddr &addr, int type)
    {
        // 1.构建一个connection
        Connection *newcon = new Connection(fd);
        newcon->SetEvents(events);
        newcon->SetConnectionType(type);
        // 设置connection的地址
        newcon->SetInetAddr(addr);
        // 将每一个connection都指向当前这个Reactor对象
        newcon->SetReactorPtr(this);

        // 1.2注册回调方法
        if (newcon->ConnectionType() == LISTENLOCKET)
        {
            // 注册监听套接字回调方法集
            newcon->RegisEventCallback(_newConnect_handle, nullptr, nullptr);
        }
        else
        {
            // 注册普通套接字回调方法集
            newcon->RegisEventCallback(_recv_handle, _send_handle, _error_hendle);
        }
        // 2.添加进epoll--即内核中
        if (!_epoller->AddEvents(newcon->SockFd(), newcon->Eevents()))
        {
            return;
        }
        // 3.添加进_connections；
        _connections.insert(std::make_pair(newcon->SockFd(), newcon));
    }
    void EnableConnectionReadWrite(int fd,bool read,bool write)
    {
        if(!IsConnectionExist(fd))
        {
            return;
        }
        uint32_t events = ((read ? EPOLLIN : 0) | (write ? EPOLLOUT : 0) | EPOLLET);
        _connections[fd]->SetEvents(events);

        //写进内核
        _epoller->ModEvents(_connections[fd]->SockFd(),events);
    }
    // 事件转发
    void Distributor()
    {
        _isrunning = true;
        int timeout = -1;//阻塞式epoll
        while (true)
        {
            OnceLoop(timeout);
        }
        _isrunning = false;
    }
    bool IsConnectionExist(int fd)
    {
        return _connections.find(fd) != _connections.end();
    }
    void SetOneConnection(handle_t newConnect_handle)
    {
        _newConnect_handle = newConnect_handle;
    }
    void SetNormalConnection(handle_t recv, handle_t send, handle_t error)
    {
        _recv_handle = recv;
        _send_handle = send;
        _error_hendle = error;
    }
    ~Reactor()
    {}

private:
    std::unordered_map<int, Connection *> _connections; // 管理所有的Connection
    std::unique_ptr<Multiplex> _epoller;                // 模板方法模式封装epoll
    struct epoll_event revents[gnum];                   // 保存epoll_wait接口返回的结果
    bool _isrunning;

private:
    handle_t _newConnect_handle; // 处理新连接
    handle_t _recv_handle;       // 处理读事件
    handle_t _send_handle;       // 处理写事件
    handle_t _error_hendle;      // 处理异常事件
};